package cn.liutao.order.service;

import cn.liutao.auth.entity.po.User;
import cn.liutao.auth.mapper.UserMapper;
import cn.liutao.common.enums.OrderEnum;
import cn.liutao.common.enums.PayEnum;
import cn.liutao.common.exception.BadRequestException;
import cn.liutao.common.exception.OrderException;
import cn.liutao.common.utils.ServletUtils;
import cn.liutao.order.entity.dto.AlipayStatusDto;
import cn.liutao.order.entity.po.OrderBill;
import cn.liutao.order.entity.po.PayBill;
import cn.liutao.order.entity.vo.AlipayVo;
import cn.liutao.order.entity.vo.OrderVo;
import cn.liutao.order.mapper.OrderBillMapper;
import cn.liutao.order.mapper.OrderMapper;
import cn.liutao.order.mapper.PayBillMapper;
import cn.liutao.websocket.SocketServer;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AreaCode;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

import static cn.liutao.order.entity.po.table.OrderBillTableDef.ORDER_BILL;
import static cn.liutao.order.entity.po.table.PayBillTableDef.PAY_BILL;

/**
 * @author: liutao
 * @description: 支付service
 * @date: 2023/12/13 14:52
 */
@Slf4j
public class PayService {
    private static String url;
    private static String alipayPublicKey;
    private static String appPrivateKey;
    private static String appID;
    private static String gateway;
    private static volatile PayService instance;
    private PayBillMapper payBillMapper;
    private OrderService orderService;
    private OrderMapper orderMapper;
    private UserMapper userMapper;
    private OrderBillMapper orderBillMapper;
    private PayService() {
        payBillMapper = ServletUtils.getMapper(PayBillMapper.class);
        orderService = OrderService.getInstance();
        orderMapper = ServletUtils.getMapper(OrderMapper.class);
        userMapper = ServletUtils.getMapper(UserMapper.class);
        orderBillMapper = ServletUtils.getMapper(OrderBillMapper.class);
        getConfig();
    }

    public static PayService getInstance() {
        if (instance == null) {
            synchronized (PayService.class) {
                if (instance == null) {
                    instance = new PayService();
                }
            }
        }

        return instance;
    }

    /**
     * 初始化支付宝配置
     */
    private static void getConfig(){
        log.info("读取支付配置文件");
        Properties properties = new Properties();
        try {
            InputStream is = AreaCode.class.getClassLoader().getResourceAsStream("alipay.properties");
            properties.load(is);
            gateway= properties.getProperty("gateway");
            appID = properties.getProperty("app_id");
            url = properties.getProperty("url");
            appPrivateKey = properties.getProperty("app_private_key");
            alipayPublicKey = properties.getProperty("alipay_public_key");
        } catch (IOException e) {
            e.printStackTrace();
            log.error("读取alipay配置文件失败：{}",e.getMessage());
        }

    }


    /**
     * 支付宝支付
     * @param payNo
     * @return
     */
    public AlipayVo alipay(String payNo) {
        //判断是否可以支付
        PayBill payBill = payBillMapper.selectOneByQuery(QueryWrapper.create().where(PAY_BILL.PAY_NO.eq(payNo)));
        if (payBill==null){
            throw new BadRequestException("支付记录不存在");
        }
        if (PayEnum.PAY_STATUS_BUY_SUCCESS.getIntValue().compareTo(payBill.getStatus())==0){
            throw new BadRequestException("已支付，请勿重复支付");
        }
        //进行支付
        String form = alipay(payBill);
        AlipayVo alipay = new AlipayVo();
        alipay.setPayForm(form);
        alipay.setPayNo(payBill.getPayNo());
        return alipay;
    }


    /**
     * 支付宝支付具体逻辑
     * @param payBill
     * @return
     */
    private String alipay(PayBill payBill){
        AlipayClient alipayClient = new DefaultAlipayClient(gateway,appID,appPrivateKey,"json","UTF-8",alipayPublicKey,"RSA2");
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        //异步接收地址，仅支持http/https，公网可访问
        request.setNotifyUrl(url+"/order/payresult");
        //同步跳转地址，仅支持http/https
//        request.setReturnUrl("");
        /******必传参数******/
        JSONObject bizContent = new JSONObject();
        //商户订单号，商家自定义，保持唯一性
        bizContent.put("out_trade_no", payBill.getPayNo());
        //支付金额，最小值0.01元
        bizContent.put("total_amount",payBill.getTotalPrice());
        //订单标题，不可使用特殊符号
        String subject = "支付宝支付";
        if (PayEnum.PAY_TYPE_EXCHANGE.getIntValue().compareTo(payBill.getType())==0){
            //余额充值
            subject = "余额充值";
        }if (PayEnum.PAY_TYPE_BUY.getIntValue().compareTo(payBill.getType())==0){
            //购买商品
            //获取订单信息
            OrderVo order = orderService.selectVoByNo(payBill.getOrderNo());
            subject = "恰饭点餐【"+order.getTable().getName()+"】";
            JSONArray goodsDetail = new JSONArray();
            order.getItemList().stream().forEach(item -> {
                JSONObject good = new JSONObject();
                good.put("name", item.getDish().getName() + ":" + item.getTaste().getName());
                good.put("quantity", item.getQuantity());
                good.put("price", item.getPrice());
                goodsDetail.add(good);
            });
            bizContent.put("goods_detail", goodsDetail);
        }
        bizContent.put("subject",subject);
        /******可选参数******/
        //手机网站支付默认传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "QUICK_WAP_WAY");
        //bizContent.put("time_expire", "2022-08-01 22:00:00");

        //// 商品明细信息，按需传入

        //// 扩展信息，按需传入
        //JSONObject extendParams = new JSONObject();
        //extendParams.put("sys_service_provider_id", "2088511833207846");
        //bizContent.put("extend_params", extendParams);

        request.setBizContent(bizContent.toString());
        AlipayTradeWapPayResponse response = null;
        try {
            response = alipayClient.pageExecute(request);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        if(response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return response.getBody();
    }

    /**
     * 获取支付结果
     * @param payNo
     * @return
     */
    public AlipayStatusDto getResult(String payNo) {
        //获取支付记录
        PayBill payBill = payBillMapper.selectOneByQuery(QueryWrapper.create().where(PAY_BILL.PAY_NO.eq(payNo)));
        if (payBill==null){
            throw new OrderException("支付记录不存在");
        }

        //查询支付状态
        AlipayStatusDto aliPayVo= queryPayResultFromAlipay(payBill.getPayNo());

        //根据支付状态更新订单状态
        saveAliPayStatus(aliPayVo);

        return aliPayVo;
    }

    /**
     * 根据支付结果修改订单状态
     * @param alipayStatusDto
     */
    public void saveAliPayStatus(AlipayStatusDto alipayStatusDto) {
        //查询支付记录
        String payNo = alipayStatusDto.getOutTradeNo();
        PayBill payBill = payBillMapper.selectOneByQuery(QueryWrapper.create().where(PAY_BILL.PAY_NO.eq(payNo)));
        if (payBill==null){
            throw new OrderException("支付记录不存在");
        }
        //判断支付类型
        if (PayEnum.PAY_TYPE_BUY.getIntValue().compareTo(payBill.getType())==0){
            saveAlipayStatusFromBuy(alipayStatusDto, payBill);
        }else if (PayEnum.PAY_TYPE_EXCHANGE.getIntValue().compareTo(payBill.getType())==0){
            saveAlipayStatusFromExchange(alipayStatusDto,payBill);
        }
    }

    /**
     * 余额充值
     * @param alipayStatusDto
     * @param payBill
     */
    private void saveAlipayStatusFromExchange(AlipayStatusDto alipayStatusDto, PayBill payBill) {
        //判断是否支付
        if (PayEnum.PAY_STATUS_BUY_SUCCESS.getIntValue().compareTo(payBill.getStatus())==0){
            return;
        }
        String tradeStatus = alipayStatusDto.getTradeStatus();
        if ("TRADE_SUCCESS".equals(tradeStatus)){
            Db.tx(()->{
                //修改用户余额
                User user = userMapper.selectOneById(payBill.getUserId());
                if (user==null){
                    throw new BadRequestException("用户不存在");
                }
                BigDecimal balance = user.getBalance();
                BigDecimal totalAmount = balance.add(payBill.getTotalPrice());
                user.setBalance(totalAmount);
                userMapper.update(user);
                //更新支付记录
                payBill.setStatus(PayEnum.PAY_STATUS_BUY_SUCCESS.getIntValue());
                payBill.setPayTime(LocalDateTime.now());
                payBill.setMethod(PayEnum.PAY_METHOD_ALIPAY.getIntValue());
                payBill.setType(PayEnum.PAY_TYPE_EXCHANGE.getIntValue());
                payBill.setAlipayNo(alipayStatusDto.getTradeNo());
                payBillMapper.update(payBill);
                return true;
            });
        }
    }

    /**
     * 购买商品
     * @param alipayStatusDto
     * @param payBill
     */
    private void saveAlipayStatusFromBuy(AlipayStatusDto alipayStatusDto, PayBill payBill) {
        String orderNo = payBill.getOrderNo();
        OrderVo order = orderService.selectVoByNo(orderNo);
        if (order==null){
            throw new OrderException("订单不存在");
        }
        if (PayEnum.PAY_STATUS_BUY_SUCCESS.getIntValue().compareTo(payBill.getStatus())==0){
            return;
        }
        String tradeStatus = alipayStatusDto.getTradeStatus();
        if ("TRADE_SUCCESS".equals(tradeStatus)){
            log.debug("修改了支付记录信息");
            Db.tx(()->{
                //更新支付记录
                payBill.setStatus(PayEnum.PAY_STATUS_BUY_SUCCESS.getIntValue());
                payBill.setPayTime(LocalDateTime.now());
                payBill.setMethod(PayEnum.PAY_METHOD_ALIPAY.getIntValue());
                payBill.setType(PayEnum.PAY_TYPE_BUY.getIntValue());
                payBill.setAlipayNo(alipayStatusDto.getTradeNo());
                payBillMapper.update(payBill);
                //更新订单记录
                order.setStatus(OrderEnum.ORDER_STATUS_NO_SERVE.getIntValue());
                order.setPayTime(LocalDateTime.now());
                orderMapper.update(order);
                //更新支付记录表
                OrderBill orderBill = orderBillMapper.selectOneByQuery(QueryWrapper.create().where(ORDER_BILL.ORDER_NO.eq(orderNo)));
                if (orderBill!=null){
                    orderBill.setPayTime(LocalDateTime.now());
                    orderBill.setPayPrice(order.getTotalPrice());
                    orderBillMapper.update(orderBill);
                }
                //像前端发送消息
                SocketServer socketServer = SocketServer.getInstance();
                String orderStr = JSONObject.toJSONString(order);
                socketServer.sendMessage(orderStr);
                return true;
            });
        }
    }

    /**
     * 查询订单状态
     * @param payNo
     * @return
     */
    private AlipayStatusDto queryPayResultFromAlipay(String payNo) {
        AlipayClient alipayClient = new DefaultAlipayClient(gateway,appID,appPrivateKey,"json","UTF-8",alipayPublicKey,"RSA2");
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no",payNo);
        request.setBizContent(bizContent.toString());
        String body = null;
        Map<String,String> payResult;
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            body =response.getBody();
            JSONObject jsonObject = JSONObject.parseObject(body);
            payResult= jsonObject.getObject("alipay_trade_query_response", Map.class);
            if (!response.isSuccess()){
                throw new BadRequestException(payResult.get("sub_msg"));
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BadRequestException(e.getMessage());
        }
        log.debug("手动查询支付结果：{}",payResult);
        AlipayStatusDto aliPayVo = new AlipayStatusDto();
        aliPayVo.setOutTradeNo(payNo);
        String tradeNo = payResult.get("trade_no");
        String tradeStatus = payResult.get("trade_status");
        String totalAmount = payResult.get("total_amount");
        aliPayVo.setTradeNo(tradeNo);
        aliPayVo.setTradeStatus(tradeStatus);
        aliPayVo.setTotalAmount(totalAmount);
        aliPayVo.setAppId(appID);
        return aliPayVo;
    }

    public PayBill saveExchangePayBill(Integer userId, BigDecimal amount) {
        PayBill payBill = new PayBill();
        payBill.setOrderNo("");
        payBill.setUserId(userId);
        String payNo = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        payBill.setPayNo(payNo);
        payBill.setStatus(PayEnum.PAY_STATUS_NO_BUY.getIntValue());
        payBill.setType(PayEnum.PAY_TYPE_EXCHANGE.getIntValue());
        payBill.setTotalPrice(amount);
        payBillMapper.insert(payBill);
        return payBill;
    }
}
